/**
 * Project Name:boar-deploy-agent 
 * File Name:AgentAspect.java 
 * Date:2017年7月3日
 */
package com.boarsoft.boar.agent;

import java.util.Arrays;
import java.util.TreeMap;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

/**
 * Agent前置通知
 * 
 * @author YangLiu
 * @CreateDate 2017年7月3日 上午11:09:30
 * @version 1.0
 * 
 * @UpdateUser 修改人名称
 * @UpdateDate 2017年7月3日 上午11:09:30
 * @UpdateRemark 修改具体的内容
 */
//@Component
//@Aspect
@Deprecated
public class AgentAspect {
	
	private static Logger logger = LoggerFactory.getLogger(AgentAspect.class);

	@Pointcut("execution(* com.boarsoft.agent.AgentService.*(..))")
	public void execAgentMethod(){
		
	}
	
	@Before(value="execAgentMethod()")
	public void injectKey(JoinPoint join) {
		Object[] args = join.getArgs();
		String methodName = join.getSignature().getName();
		Class<?> clazz = join.getTarget().getClass();
		String className = clazz.getName();
		ClassPool classPool = ClassPool.getDefault();
		ClassClassPath classPath = new ClassClassPath(clazz);
		classPool.insertClassPath(classPath);
		try {
			CtClass ctCls = classPool.getOrNull(className);
			CtClass paramCtCls = null;
			CtMethod ctMtd = null;
			if (args != null && args.length > 0 && ctCls != null) {
				CtClass[] paramCtClses = new CtClass[args.length];
				int i = 0;
				String paramType = null;
				for (Object arg : args) {
					if (arg != null) {
						paramType = arg.getClass().getName();
					} else {
						paramType = "java.lang.String";
					}
					paramCtCls = classPool.get(paramType);
					paramCtClses[i] = paramCtCls;
					i++;
				}
				ctMtd = ctCls.getDeclaredMethod(methodName, paramCtClses);
				MethodInfo methodInfo = ctMtd.getMethodInfo();
				CodeAttribute codeAttr = methodInfo.getCodeAttribute();
				LocalVariableAttribute attr = (LocalVariableAttribute) codeAttr.getAttribute(LocalVariableAttribute.tag);
				if (attr != null) {
					int pos = Modifier.isStatic(ctMtd.getModifiers()) ? 0 : 1;
					String[] paramNames = new String[ctMtd.getParameterTypes().length];
					TreeMap<Integer, String> sortMap = new TreeMap<Integer, String>();
					for (i=0; i<attr.tableLength(); i++) {
						sortMap.put(attr.index(i), attr.variableName(i));
					}
					paramNames = Arrays.copyOfRange(sortMap.values().toArray(new String[0]), pos, pos + paramNames.length);
					for (i=0; i<paramNames.length; i++) {
						if ("taskKey".equals(paramNames[i])) {
							MDC.put("logKey", (String) args[i]);
							break;
						}
					}
				}
			} 
		} catch (Exception e) {
			logger.error("Cannot record agent logs for method {}.{} with parameters {} for ", 
					className, methodName, Arrays.asList(args), e);
		}
		
	}
}
